﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using ERF.Input;
using Microsoft.Xna.Framework.Graphics;

namespace ERF {
    /// <summary>
    /// The abstract ERFGame class which games should inherit from.
    /// </summary>
    public abstract class ERFGame : Game {
        private GraphicsDeviceManager graphics;
        private MultiSampleType[] supportedMultiSampleTypes = null;
        protected MultiSampleType currentMultiSampleType;

        public abstract SceneGraph CurrentSceneGraph {
            get;
            set;
        }

        public abstract IInputHandler Input {
            get;
        }

        public abstract Camera Camera {
            get;
            set;
        }

        public abstract SoundHandler SoundHandler {
            get;
        }

        public abstract StateMachine StateMachine {
            get;
        }

        public abstract NetworkHandler NetworkHandler {
            get;
        }
        public abstract PlayerHandler PlayerHandler {
            get;
        }

        public bool IsFullscreen
        {
            get
            {
                return this.graphics.IsFullScreen;
            }
            set
            {
                if (this.IsFullscreen ^ value)
                    this.graphics.ToggleFullScreen();
            }
        }

        public ERFGame()
        {
            this.graphics = new GraphicsDeviceManager(this);
            this.graphics.PreparingDeviceSettings += new EventHandler<PreparingDeviceSettingsEventArgs>(graphics_PreparingDeviceSettings);
        }

        void graphics_PreparingDeviceSettings(object sender, PreparingDeviceSettingsEventArgs e)
        {
            e.GraphicsDeviceInformation.PresentationParameters.MultiSampleType = this.currentMultiSampleType;
        }

        protected override void Initialize()
        {
            this.currentMultiSampleType = base.GraphicsDevice.PresentationParameters.MultiSampleType;
            base.Initialize();
        }

        public virtual void SetResolution(int width, int height)
        {
            this.graphics.PreferredBackBufferHeight = height;
            this.graphics.PreferredBackBufferWidth = width;
            this.graphics.ApplyChanges();
        }

        public virtual void ToogleFullscreen()
        {
            if (this.graphics.IsFullScreen)
            {
                this.graphics.PreferredBackBufferWidth = 800;
                this.graphics.PreferredBackBufferHeight = 600;
            }
            else
            {
                this.graphics.PreferredBackBufferWidth = base.GraphicsDevice.DisplayMode.Width;
                this.graphics.PreferredBackBufferHeight = base.GraphicsDevice.DisplayMode.Height;
            }
            this.graphics.ApplyChanges();
            this.graphics.ToggleFullScreen();
        }

        /// <summary>
        /// Returns an array of supported multisampletypes, up to 10 samples.
        /// </summary>
        /// <returns>An array of supported multisampletypes.</returns>
        public MultiSampleType[] GetSupportedMultiSampleTypes() { 
            if(this.supportedMultiSampleTypes == null)
            {
                SurfaceFormat surfaceFormat = base.GraphicsDevice.DisplayMode.Format;
                bool passedCheck = false;
                List<MultiSampleType> multiSampleTypes = new List<MultiSampleType>();

                // Check every even multisample type up to 10 samples.
                // If one check fails, the higher samples will not be checked.
                if ((passedCheck = base.GraphicsDevice.CreationParameters.Adapter.CheckDeviceMultiSampleType(DeviceType.Hardware, surfaceFormat, true, MultiSampleType.TwoSamples)))
                    multiSampleTypes.Add(MultiSampleType.TwoSamples);

                if(passedCheck &&
                    (passedCheck = base.GraphicsDevice.CreationParameters.Adapter.CheckDeviceMultiSampleType(DeviceType.Hardware, surfaceFormat, true, MultiSampleType.FourSamples)))
                    multiSampleTypes.Add(MultiSampleType.FourSamples);

                if(passedCheck &&
                    (passedCheck = base.GraphicsDevice.CreationParameters.Adapter.CheckDeviceMultiSampleType(DeviceType.Hardware, surfaceFormat, true, MultiSampleType.SixSamples)))
                    multiSampleTypes.Add(MultiSampleType.SixSamples);

                if(passedCheck &&
                    (passedCheck = base.GraphicsDevice.CreationParameters.Adapter.CheckDeviceMultiSampleType(DeviceType.Hardware, surfaceFormat, true, MultiSampleType.EightSamples)))
                    multiSampleTypes.Add(MultiSampleType.EightSamples);

                if(passedCheck &&
                    (passedCheck = base.GraphicsDevice.CreationParameters.Adapter.CheckDeviceMultiSampleType(DeviceType.Hardware, surfaceFormat, true, MultiSampleType.TenSamples)))
                    multiSampleTypes.Add(MultiSampleType.TenSamples);

                this.supportedMultiSampleTypes = multiSampleTypes.ToArray();
            }

            return this.supportedMultiSampleTypes;
        }

        public MultiSampleType CurrentMultiSampleType 
        {
            get { return this.currentMultiSampleType; }
            set
            {
                this.currentMultiSampleType = value;
                base.GraphicsDevice.PresentationParameters.MultiSampleType = value;
                base.GraphicsDevice.Reset(base.GraphicsDevice.PresentationParameters);
            }
        }

        public bool VerticalSync
        {
            get { return this.graphics.SynchronizeWithVerticalRetrace; }
            set { this.graphics.SynchronizeWithVerticalRetrace = value; }
        }
    }
}
